from django import forms
from django.db.models import Q

from oracle.models import OPermission, OMenu


class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'


class MenuForm(BaseForm):
    title = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'NAME'}),
        max_length=30,
        strip=True,
        label="菜单名",
        error_messages={
            "required": "名称字段不能为空",
        }
    )
    menu_icon = forms.CharField(
        required=False,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'ICON'}),
        max_length=30,
        strip=True,
        label="菜单图标",
        help_text='全部图标信息请访问<a href="/oracle/menu/iconlist/" target="_blank">图标列表</a>选择合适图标代码进行填写',
    )
    parent = forms.ModelChoiceField(
        required=False,
        queryset=OMenu.objects.filter(link_to_permission__isnull=True, status=0),
        to_field_name="key",
        widget=forms.widgets.Select(),
        label="上级菜单",
        empty_label="菜单列表(和页面菜单层级相同)",
        error_messages={
            "invalid_choice": "没有选项定义，请选择一个符合要求的选项",
        }
    )

    class Meta:
        model = OMenu
        fields = ("key", "title", "menu_icon", "status", "level", "parent")

    def clean_title(self):
        title = self.cleaned_data["title"]
        menu_key = self.instance.key
        try:
            obj = OMenu.objects.get(title=title)
            if menu_key and obj.key == menu_key:
                return title
        except OMenu.DoesNotExist:
            return title
        raise forms.ValidationError("此菜单名称已存在.")

    def clean_parent(self):
        parent = self.cleaned_data['parent']
        if not parent:
            return None
        if not parent:
            raise forms.ValidationError("所指定的上级菜单不存在")
        elif parent.link_to_permission:
            raise forms.ValidationError("此节点不能做上级菜单")
        else:
            return parent


class MenuCreateForm(MenuForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if "status" in self.fields:
            self.fields["status"].required = False
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = False
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
            }
        if "level" in self.fields:
            self.fields["level"].required = False
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }


class MenuUpdateForm(MenuForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if "status" in self.fields:
            self.fields["status"].required = True
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = True
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
            }
        if "level" in self.fields:
            self.fields["level"].required = True
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }


class PermissionForm(BaseForm):
    title = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'TITLE'}),
        max_length=30,
        strip=True,
        label="权限名称",
        error_messages={
            "required": "标题字段不能为空",
            "unique": "标题已存在，请重新命名。",
        },
    )
    url = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'URL'}),
        max_length=30,
        strip=True,
        label="URL",
        error_messages={
            "required": "url字段不能为空",
            "unique": "url已存在，请重新输入。",
        },
    )
    name = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'NAME'}),
        max_length=30,
        strip=True,
        label="权限别名",
        error_messages={
            "required": "别名字段不能为空",
            "unique": "别名已存在，请重新命名。",
        },
    )
    rel = forms.ModelChoiceField(
        required=False,
        queryset=OMenu.objects.filter(menu_node_parent__isnull=True, link_to_permission__isnull=True, status=0),
        to_field_name="key",
        widget=forms.widgets.Select(),
        label="关联菜单",
        empty_label="不关联菜单",
        error_messages={
            "invalid_choice": "关联菜单不符合要求。",
        }
    )

    class Meta:
        model = OPermission
        fields = ("key", "title", "url", "name", "status", "level", "rel")

    def save_rel(self, permission):
        rel = self.cleaned_data['rel']
        if rel:
            rel.link_to_permission = permission
            rel.save()

    def save(self, commit=True):
        permission = super().save()
        self.save_rel(permission)
        return permission


class PermissionCreateForm(PermissionForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if "status" in self.fields:
            self.fields["status"].required = False
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = False
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
            }
        if "level" in self.fields:
            self.fields["level"].required = False
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }


class PermissionUpdateForm(PermissionForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields['rel'].queryset = OMenu.objects.filter(
            Q(menu_node_parent__isnull=True, link_to_permission__isnull=True, status=0) |
            Q(key=self.instance.omenu.key, status=0)
        )
        self.fields['rel'].instance = self.instance.omenu
        self.fields['rel'].initial = self.instance.omenu.key
        self.instance.rel = self.instance.omenu.key

        if "status" in self.fields:
            self.fields["status"].required = True
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = True
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
            }
        if "level" in self.fields:
            self.fields["level"].required = True
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }

    def save_rel(self, permission):
        rel = self.cleaned_data['rel']
        if rel:
            OMenu.objects.filter(link_to_permission=self.instance, status=0).update(link_to_permission=None)
            rel.link_to_permission = permission
            rel.save()


class MultiPermissionForm(forms.ModelForm):
    title = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'TITLE'}),
        max_length=30,
        strip=True,
        label="标题",
        error_messages={
            "required": "标题字段不能为空",
            "unique": "标题已存在，请重新命名",
        }
    )
    url = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'URL'}),
        max_length=256,
        strip=True,
        label="URL",
        error_messages={
            "required": "url字段不能为空",
            "unique": "url已存在，请重新确认后输入",
        }
    )
    name = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'NAME'}),
        max_length=120,
        strip=True,
        label="名称",
        error_messages={
            "required": "名称字段不能为空",
            "unique": "名称已存在，请重新命名",
        }
    )

    class Meta:
        model = OPermission
        fields = ("key", "title", "url", "name", "status", "level")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 统一给Form生成字段添加样式
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'


class MultiAddPermissionForm(MultiPermissionForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if "status" in self.fields:
            self.fields["status"].required = False
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = False
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
                "unique": "索引已存在，请重新输入",
            }
        if "level" in self.fields:
            self.fields["level"].required = False
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }


class MultiEditPermissionForm(MultiPermissionForm):
    id = forms.CharField(
        widget=forms.widgets.HiddenInput(),
        label="id",
        required=True,
        disabled=True,
    )

    class Meta:
        model = OPermission
        fields = ("id", "key", "title", "url", "name", "status", "level")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if "status" in self.fields:
            self.fields["status"].required = True
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = True
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
                "unique": "索引已存在，请重新输入",
            }
        if "level" in self.fields:
            self.fields["level"].required = True
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }


class MenuLinkAddForm(forms.ModelForm):
    title = forms.CharField(
        required=True,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'TITLE'}),
        max_length=30,
        strip=True,
        label="菜单名称",
        error_messages={
            "required": "菜单名称字段不能为空",
            "unique": "菜单名已存在，请重新命名",
        }
    )
    menu_icon = forms.CharField(
        required=False,
        widget=forms.widgets.TextInput(attrs={'placeholder': 'ICON'}),
        max_length=30,
        strip=True,
        label="菜单图标",
    )
    link_to_permission = forms.ModelChoiceField(
        required=False,
        to_field_name="key",
        queryset=OPermission.objects.filter(omenu__isnull=True, status=0),
        widget=forms.widgets.Select(),
        empty_label="------",
        label="关联权限",
        error_messages={
            "invalid_choice": "关联权限不符合要求。",
        }
    )
    parent = forms.ModelChoiceField(
        required=False,
        to_field_name="key",
        queryset=OMenu.objects.filter(link_to_permission__isnull=True, status=0),
        widget=forms.widgets.Select(),
        empty_label="------",
        label="上级菜单",
        error_messages={
            "invalid_choice": "上级菜单不符合要求。",
        }
    )
    menu_inner = forms.ModelChoiceField(
        required=False,
        to_field_name="key",
        queryset=OMenu.objects.filter(link_to_permission__isnull=False, menu_inner__isnull=True, status=0),
        widget=forms.widgets.Select(),
        empty_label="------",
        label="关联菜单",
        error_messages={
            "invalid_choice": "关联菜单不符合要求。",
        }
    )

    class Meta:
        model = OMenu
        fields = ("key", "title", "menu_icon", "link_to_permission", "parent", "menu_inner", "status", "level")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name in self.fields:
            self.fields[name].widget.attrs['class'] = 'form-control'

        if "status" in self.fields:
            self.fields["status"].required = False
            self.fields["status"].error_messages = {
                "required": "状态字段不能为空",
                "invalid_choice": "没有选项定义，请选择一个符合要求的选项"
            }
        if "key" in self.fields:
            self.fields["key"].required = False
            self.fields["key"].error_messages = {
                "required": "索引字段不能为空",
                "unique": "索引已存在，请重新输入",
            }
        if "level" in self.fields:
            self.fields["level"].required = False
            self.fields["level"].error_messages = {
                "required": "等级字段不能为空",
                "invalid": "非数字，请传入一个数字"
            }

    def clean_parent(self):
        menu_parent = self.cleaned_data['parent']
        menu_inner = self.cleaned_data.get('menu_inner')
        if menu_parent and menu_inner:
            raise forms.ValidationError("父级菜单不能和关联菜单同时设置")
        return menu_parent

    def clean_menu_inner(self):
        menu_parent = self.cleaned_data.get('parent')
        menu_inner = self.cleaned_data['menu_inner']
        if menu_parent and menu_inner:
            raise forms.ValidationError("父级菜单不能和关联菜单同时设置")
        return menu_inner


class MenuLinkEditForm(MenuLinkAddForm):
    id = forms.CharField(
        widget=forms.widgets.HiddenInput(),
        label="id",
        required=True,
        disabled=True,
    )

    class Meta:
        model = OMenu
        fields = ("id", "key", "title", "menu_icon", "link_to_permission", "parent", "menu_inner", "status", "level")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        permission_key = self.instance.link_to_permission
        if permission_key:
            permission_key = permission_key.key
        else:
            permission_key = self.initial["link_to_permission"]
        if permission_key:
            self.fields['link_to_permission'].queryset = OPermission.objects.filter(
                Q(omenu__isnull=True, status=0) | Q(key=permission_key, status=0)
            )

        parent_key = self.instance.parent
        if parent_key:
            parent_key= parent_key.key
        else:
            parent_key = self.initial["parent"]
        if parent_key:
            self.fields['parent'].queryset = OMenu.objects.filter(
                Q(link_to_permission__isnull=True, status=0) | Q(key=parent_key, status=0)
            )

        menu_inner_key = self.instance.menu_inner
        if not menu_inner_key:
            menu_inner_key = self.initial["menu_inner"]
        if menu_inner_key:
            self.fields['menu_inner'].queryset = OMenu.objects.filter(
                Q(menu_node_parent__isnull=True, menu_inner__isnull=True, status=0) |
                Q(key=menu_inner_key, status=0)
            )

        if "status" in self.fields:
            self.fields["status"].required = False
        if "key" in self.fields:
            self.fields["key"].required = False
        if "level" in self.fields:
            self.fields["level"].required = False

    def clean_parent(self):
        menu_parent = self.cleaned_data['parent']
        menu_inner = self.cleaned_data.get('menu_inner')
        if menu_parent and menu_inner:
            raise forms.ValidationError("父级菜单不能和关联菜单同时设置")
        return menu_parent

    def clean_menu_inner(self):
        menu_parent = self.cleaned_data.get('parent')
        menu_inner = self.cleaned_data['menu_inner']
        if menu_parent and menu_inner:
            raise forms.ValidationError("父级菜单不能和关联菜单同时设置")
        return menu_inner
